use serialport::{SerialPort, Parity, DataBits, StopBits};
use std::time::Duration;
use std::thread;
use std::io::{Read, Write, ErrorKind};
use std::sync::mpsc as stdc;
use tokio::sync::mpsc as toc;
use tokio::task;
use log::{info, debug, warn};
use crate::util;
use crate::serial::{SerialStdReceiver, SerialReceiver, ConnectSerialConfig};


/// 获取串口列表
pub fn get_ports() -> serialport::Result<Vec<String>> {
    let vi = serialport::available_ports()?;
    let mut vs = vec![];
    for x in vi { vs.push(x.port_name); }
    Ok(vs)
}

/// 打开串口
pub fn open<'a>(path: impl Into<std::borrow::Cow<'a, str>>, serial_config: &ConnectSerialConfig) -> serialport::Result<Box<dyn SerialPort>> {
    let data_bits = match serial_config.data_bits {
        5 => { DataBits::Five }
        6 => { DataBits::Six }
        7 => { DataBits::Seven }
        _ => { DataBits::Eight }
    };

    let stop_bits = match serial_config.stop_bits {
        2 => { StopBits::Two }
        _ => { StopBits::One }
    };

    let parity = match serial_config.parity {
        1 => { Parity::Odd }
        2 => { Parity::Even }
        _ => { Parity::None }
    };
    serialport::new(path, serial_config.baud_rate)
        .timeout(Duration::from_millis(serial_config.timeout_millis))
        .data_bits(data_bits)
        .stop_bits(stop_bits)
        .parity(parity)
        .open()
}

/// 线程监听
pub fn listen(mut port: Box<dyn SerialPort>, buffer_box: Box<[u8]>, channel_cap: usize) -> SerialStdReceiver
{
    let (s, r) = stdc::sync_channel(channel_cap);
    thread::spawn(move || {
        loop {
            let mut vec = Vec::new();
            'inner: loop {
                let mut u = buffer_box.clone();
                match port.read(u.as_mut()) {
                    Ok(size) => {
                        let mut v = u[..size].to_vec();
                        vec.append(&mut v);
                        if let Err(e) = s.send((vec.len(), vec.into_boxed_slice())) {
                            warn!("{}", e);
                        }
                        break 'inner;
                    }
                    Err(e) => {
                        debug!("listen err to continue : `{}`",e);
                        continue;
                    }
                };
            }
        }
    });
    r
}

/// 线程监听 异步
pub async fn listen_async(mut port: Box<dyn SerialPort>, buffer_size: usize, read_delay_millis: u64, reread_times: u64) -> SerialReceiver
{
    let (s, r) = toc::channel(1);
    task::spawn(async move {
        loop {
            let mut vec = Vec::new();
            let mut reread = 0;
            'inner: loop {
                // debug!("`{}` read times : `{}` and buffer: `{:?}`",port.name().unwrap(),reread,vec);
                let mut u = util::creat_boxed_u8_slice(buffer_size);
                match port.read(u.as_mut()) {
                    Ok(size) => {
                        let mut v = u[..size].to_vec();
                        vec.append(&mut v);
                    }
                    Err(e) => {
                        if e.kind().ne(&ErrorKind::TimedOut) {
                            warn!("unknown err in serial listen : `{}`",e);
                        }
                        tokio::time::sleep(Duration::from_millis(read_delay_millis)).await;
                    }
                };
                if !vec.is_empty() { reread += 1; } else { continue; }
                if reread > reread_times {
                    debug!("serial read:`{:?}`",vec);
                    if let Err(e) = s.send((vec.len(), vec.into_boxed_slice()))
                        .await { warn!("{}", e); }
                    if let Err(e) = s.send((0, Vec::new().into_boxed_slice()))
                        .await { warn!("{}", e); }
                    break 'inner;
                }
            }
        }
    });
    r
}

/// 线程输出
pub fn chant(mut port: Box<dyn SerialPort>, receiver: stdc::Receiver<Box<[u8]>>) {
    thread::spawn(move || {
        loop {
            match receiver.recv() {
                Ok(u) => {
                    if let Err(e) = port.write(u.as_ref()) {
                        warn!("{}", e);
                        break;
                    }
                }
                Err(e) => {
                    warn!("{}", e);
                    break;
                }
            }
        }
    });
}

/// 线程输出 异步
pub async fn chant_async(mut port: Box<dyn SerialPort>, mut receiver: toc::Receiver<Box<[u8]>>) {
    task::spawn(async move {
        loop {
            if let Some(u) = receiver.recv().await {
                info!("send -> `{:?}`",&u);
                if let Err(e) = port.write(u.as_ref()) {
                    warn!("{}", e);
                    break;
                }
            }
        }
    });
}

#[cfg(test)]
mod tests {}